package com.xinyun.server;

import com.xinyun.server.protocol.ProtocolData;
import com.xinyun.server.protocol.ProtocolDataHeader;
import com.xinyun.server.protocol.receive.InverterData;
import com.xinyun.server.protocol.receive.InverterWarnData;
import com.xinyun.server.protocol.receive.LeakWarnData;
import com.xinyun.server.protocol.receive.RegisterBoardId;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * Created by bubusy on 16/5/21.
 */
public class ProtocolHandler extends ChannelInboundHandlerAdapter {

    private Log log = LogFactory.getLog(ProtocolHandler.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ProtocolData pd = (ProtocolData) msg;
        log.debug(pd);
        try {
            int msgType = pd.getHeader().getMsgType();

            switch (msgType) {
                case 1:
                    //注册board id
                    this.handleBoardId(ctx, pd);
                    break;
                case 3:
                    //心跳处理
                    this.handleHeartbeat(ctx, pd);
                    break;
                case 9:
                    this.handleWarn(ctx, pd);
                    break;
                case 7:
                    this.handleInverterData(ctx, pd);
                    break;
                case 11:
                    this.handleOneInverterData(ctx, pd);
                    break;
                default:
                    log.info("无效的协议, msg type: " + msgType);
                    break;
            }

        } finally {

        }
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        ChannelManager.addChannel(ctx.channel());
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }


    private void handleHeartbeat(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        //心跳数据不做处理
        return;

//        ProtocolDataHeader pdh = new ProtocolDataHeader();
//        pdh.setMsgType(3);
//        pdh.setLength(1);
//        ByteBuf body = channelHandlerContext.alloc().buffer(1);
//        body.writeByte(22);
//        ProtocolData pd = new ProtocolData(pdh, body);
//        channelHandlerContext.writeAndFlush(pd);
    }

    private void handleBoardId(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        RegisterBoardId registerBoardId = RegisterBoardId.parseFromProtocolData(protocolData);
        String boardId = registerBoardId.boardId;
        ChannelManager.updateChannelBoardId(channelHandlerContext.channel(), boardId);
    }

    private void handleWarn(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        ProtocolDataHeader header = protocolData.getHeader();
        if (header.getB4() == 1) {
            InverterWarnData inverterWarnData = InverterWarnData.parseFromProtocolData(protocolData);
            //TODO save warn
            log.debug(inverterWarnData);
        }
        if (header.getB4() == 2) {
            LeakWarnData leakWarnData = LeakWarnData.parseFromProtocolData(protocolData);
            //TODO send warn use wechat
        }

    }

    private void handleInverterData(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        InverterData inverterData = InverterData.parseFromProtocolData(protocolData);
        log.debug(inverterData);
        if (inverterData != null) {
            //TODO

            this.saveInverterData(inverterData);

        }
        //TODO
    }

    private void handleOneInverterData(ChannelHandlerContext channelHandlerContext, ProtocolData protocolData) {
        InverterData inverterData = InverterData.parseFromProtocolData(protocolData);
        log.debug(inverterData);
        if (inverterData != null) {
            //TODO
            this.saveInverterData(inverterData);

        }
        //TODO
    }


    private void saveInverterData(InverterData inverterData) {
        QueryRunner runner = new QueryRunner(DB.dataSource);

        String sql = "insert into z_phaethon_meter_data " +
                "(meter_id,user_id,DCU1,DCI1,DCU2,DCI2,DCU3,DCI3,DCU4,DCI4,ACUA,ACIA,ACUB,ACIB,ACUC,ACIC," +
                "IVTemp,TotGenCap,IVStatus,IVError,IVMode,FR,IVRun,MonthGenCap,LastMonthGenCap,DayGenCap,LastDayGenCap," +
                "PowerLimitPercent,ActivePower,ReactivePower,ApparentPower,PowerFactor,IVType,board_temp1,board_temp2," +
                "current_leak,board_sum_gen,board_sum_use,board_time,created_at) " +
                "values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

        Date boardTime = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd H:m:s");
            boardTime = sdf.parse(inverterData.time);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        try {

            runner.update(sql, 1, 1, inverterData.dcu1, inverterData.dci1, inverterData.dcu2, inverterData.dci2,
                    inverterData.dcu3, inverterData.dci3, inverterData.dcu4, inverterData.dci4, inverterData.acua, inverterData.acia,
                    inverterData.acub, inverterData.acib, inverterData.acuc, inverterData.acic, inverterData.ivtemp, inverterData.tolgencap,
                    inverterData.ivstatus, inverterData.iverror, inverterData.ivmode, inverterData.fr, inverterData.ivrun, inverterData.monthgencap,
                    inverterData.lastmonthgencap, inverterData.daygencap, inverterData.lastdaygencap, inverterData.powerlimitpercent,
                    inverterData.activepower, inverterData.reactivepower, inverterData.apparentpower, inverterData.powerfactor,
                    inverterData.ivtype, inverterData.boardtemp1, inverterData.boardtemp2, inverterData.currentleak,
                    inverterData.boardsumgen, inverterData.boardsumuse, boardTime, new Date());

            log.debug("save to db success");
        } catch (SQLException e) {
            log.debug(e);
            e.printStackTrace();
            DbUtils.printStackTrace(e);
        } finally {

            //DbUtils.closeQuietly();
        }

    }
}
